package com.atguigu.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.constant.MqConst;
import com.atguigu.entity.CartInfo;
import com.atguigu.entity.OrderDetail;
import com.atguigu.entity.OrderInfo;
import com.atguigu.enums.OrderStatus;
import com.atguigu.enums.ProcessStatus;
import com.atguigu.executor.MyExecutor;
import com.atguigu.feign.CartFeignClient;
import com.atguigu.feign.ProductFeignClient;
import com.atguigu.mapper.OrderInfoMapper;
import com.atguigu.service.OrderDetailService;
import com.atguigu.service.OrderInfoService;
import com.atguigu.util.HttpClientUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.amqp.core.Correlation;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * <p>
 * 订单表 订单表 服务实现类
 * </p>
 *
 * @author hachimen
 * @since 2021-09-07
 */
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CartFeignClient cartFeignClient;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Value("${cancel.order.delay}")
    private Integer cancelOrderDelay;


    @Override
    public String generateTradeNo(String userId) {
        //生成流水号并放入redis，随后返回
        String uuid = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set("user:"+userId+":tradeNo",uuid);
        return uuid;
    }

    @Override
    public Boolean checkTradeNo(String tradeNo, String userId) {
        //验证流水号
        String redisTradeNo = (String) redisTemplate.opsForValue().get("user:" + userId + ":tradeNo");
        return tradeNo.equals(redisTradeNo);
    }

    @Override
    public void deleteTradeNo(String tradeNo, String userId) {
        //删除流水号
        redisTemplate.delete("user:" + userId + ":tradeNo");
    }

    @Override
    public List<String> checkStockAndPrice(OrderInfo orderInfo, String userId) {
        //验证价格和库存  http://localhost:8100/hasStock?skuId=" + skuId + "&num=" + skuNum
        List<String> warningMsgList = new ArrayList<>();
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<CompletableFuture> completableFutureList = new ArrayList<>();
        for (OrderDetail orderDetail : orderDetailList) {

            String skuNum = orderDetail.getSkuNum();
            Long skuId = orderDetail.getSkuId();
            BigDecimal orderPrice = orderDetail.getOrderPrice();

            CompletableFuture<Void> stockCompletableFuture = CompletableFuture.runAsync(() -> {
                //验证库存
                String stockFlag = HttpClientUtil.doGet("http://localhost:8100/hasStock?skuId=" + skuId + "&num=" + skuNum);
                if (stockFlag == null || "0".equals(stockFlag)) {
                    warningMsgList.add(orderDetail.getSkuName() + "库存不足");
                }
            }, MyExecutor.getInstance());
            completableFutureList.add(stockCompletableFuture);

            CompletableFuture<Void> priceCompletableFuture = CompletableFuture.runAsync(() -> {
                //验证价格
                BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
                if (orderPrice == null || !orderPrice.equals(skuPrice)) {
                    warningMsgList.add(orderDetail.getSkuName() + "价格发生了变化");
                    cartFeignClient.queryFromDbToRedis(userId);
                }
            }, MyExecutor.getInstance());
            completableFutureList.add(priceCompletableFuture);


        }

        //线程全部完成后继续
        CompletableFuture[] completableFutures = new CompletableFuture[completableFutureList.size()];
        CompletableFuture.allOf(completableFutureList.toArray(completableFutures)).join();
        return warningMsgList;
    }

    @Override
    public Long saveOrderAndDetail(OrderInfo orderInfo,String userId) {//保存订单和订单详情到数据库
        //提交订单

        //订单状态
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        //商品对外订单号  格式 时间戳+6位随机数+4位userId
        String outTradeNo = System.currentTimeMillis()+String.format("%06d",new Random().nextInt(999999))+String.format("%04d",Integer.parseInt(userId));
        orderInfo.setOutTradeNo(outTradeNo);
        //订单主体信息
        orderInfo.setTradeBody("我的购物商品");
        //设置订单支付过期时间 设置的是一天 默认一般30
        orderInfo.setCreateTime(new Date());
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,1);
        orderInfo.setExpireTime(calendar.getTime());
        //订单进程状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        //商品的总价格 orderInfo.setTotalMoney(new BigDecimal(0.01));
        baseMapper.insert(orderInfo);
        //b.保存订单详情信息
        //该商品详情属于哪个订单
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList) {
            orderDetail.setOrderId(orderInfo.getId());
        }
        orderDetailService.saveBatch(orderDetailList);
        //MQ延时取消订单
        rabbitTemplate.convertAndSend(MqConst.CANCEL_ORDER_EXCHANGE,
                MqConst.CANCEL_ORDER_ROUTE_KEY,
                orderInfo.getId(),correlationDate -> {
            correlationDate.getMessageProperties().setDelay(cancelOrderDelay);
            return correlationDate;
                });
        return orderInfo.getId();
    }

    @Override
    public void updateOrderStatus(OrderInfo orderInfo, ProcessStatus processStatus) {
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setProcessStatus(processStatus.name());
        baseMapper.updateById(orderInfo);
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = baseMapper.selectById(orderId);
        if(orderInfo != null){
            QueryWrapper<OrderDetail> wrapper = new QueryWrapper<>();
            wrapper.eq("order_id",orderId);
            List<OrderDetail> orderDetailList = orderDetailService.list(wrapper);
            orderInfo.setOrderDetailList(orderDetailList);
        }
        return orderInfo;
    }

    @Override
    public void sendMsgToWarehouse(OrderInfo orderInfo) {
        //发消息改库存

        //封装数据
        Map<String, Object> wareHouseDataMap  = assembWareHouseData(orderInfo);
        String wareHouseDataJson = JSON.toJSONString(wareHouseDataMap);
        rabbitTemplate.convertAndSend(MqConst.DECREASE_STOCK_EXCHANGE,MqConst.DECREASE_STOCK_ROUTE_KEY,wareHouseDataJson);
    }

    @Override
    public List<Map<String,Object>> spiltOrder(Long orderId, String wareHouseIdSkuIdMapJson) {
        //数据格式 [{"wareHouseId":"1","skuIdList":["18","19"]},{"wareHouseId":"2","skuIdList":["30"]}]
        List<Map<String,Object>> childOrderInfoMapList = new ArrayList<>();
        OrderInfo originalOrder = getOrderInfo(orderId);
        List<Map> wareHouseIdSkuIdMapList = JSON.parseArray(wareHouseIdSkuIdMapJson, Map.class);
        for (Map wareHouseIdSkuIdMap : wareHouseIdSkuIdMapList) {
            String wareHouseId = (String)wareHouseIdSkuIdMap.get("wareHouseId");//仓库id
            List<String> skuIdList = (List<String>)wareHouseIdSkuIdMap.get("skuIdList");//仓库中所有的skuid集合

            OrderInfo childOrder = new OrderInfo();
            BeanUtils.copyProperties(originalOrder,childOrder);
            childOrder.setId(null);//让其自增
            childOrder.setParentOrderId(originalOrder.getId());//设置拆单的父id
            childOrder.setWareHouseId(wareHouseId);//设置仓库id
            List<OrderDetail> originalOrderDetailList = originalOrder.getOrderDetailList();
            List<OrderDetail> childOrderDetailList = new ArrayList<>();
            BigDecimal totalMoney = new BigDecimal(0);
            for (OrderDetail originalOrderDetail : originalOrderDetailList) {
                for (String skuId : skuIdList) {
                    if(Long.parseLong(skuId) == originalOrderDetail.getSkuId()){
                        //匹配到sku商品
                        childOrderDetailList.add(originalOrderDetail);
                        totalMoney = totalMoney.add(originalOrderDetail.getOrderPrice().multiply(new BigDecimal(originalOrderDetail.getSkuNum())));
                    }
                }
            }
            childOrder.setTotalMoney(totalMoney);//设置总金额
            childOrder.setOrderDetailList(childOrderDetailList);//设置订单详情

            saveOrderAndDetail(childOrder,childOrder.getUserId()+"");//保存订单和订单详情到数据库
            Map<String, Object> assembWareHouseDataMap = assembWareHouseData(childOrder);//封装成库存需要的map格式
            //放入返回的list中
            childOrderInfoMapList.add(assembWareHouseDataMap);

        }
        updateOrderStatus(originalOrder,ProcessStatus.SPLIT);//更改订单状态为已拆单
        return childOrderInfoMapList;
    }

    private Map<String, Object> assembWareHouseData(OrderInfo orderInfo) {//封装成库存需要的map格式
        Map<String, Object> dataMap  = new HashMap<>();
        dataMap.put("orderId",orderInfo.getId());
        dataMap.put("consignee",orderInfo.getConsignee());
        dataMap.put("consigneeTel",orderInfo.getConsigneeTel());
        dataMap.put("orderComment",orderInfo.getOrderComment());
        dataMap.put("orderBody",orderInfo.getTradeBody());
        dataMap.put("deliveryAddress",orderInfo.getDeliveryAddress());
        dataMap.put("paymentWay",2);
        //TODO 这里要添加一个非常重要的字段
        dataMap.put("wareId",orderInfo.getWareHouseId());
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<Map<String,Object>> orderDetailMapList = new ArrayList<>();
        for (OrderDetail orderDetail : orderDetailList) {
            Map<String, Object> orderDetailMap = new HashMap<>();
            orderDetailMap.put("skuId",orderDetail.getSkuId());
            orderDetailMap.put("skuNum",orderDetail.getSkuNum());
            orderDetailMap.put("skuName",orderDetail.getSkuName());
            orderDetailMapList.add(orderDetailMap);
        }
        dataMap.put("details",orderDetailMapList);
        return dataMap;
    }
}
